﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ibba.agil.core.common
{
   
    public abstract class DataTransferObject : DataTransferContainerObj,  ICloneable
    {
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        public void Bind(IDataEntity data)
        {
            
            var bind = true;
            this.Parse(data,
                        this,
                        bind,
                        ParseDataList(data));
        }

        /// <summary>
        /// Preenche o DTO atraves de uma data
        /// </summary>
        /// <param name="data"></param>
        public void Fill(IDataEntity data)
        {
            var bind = false;
            this.Parse( data, 
                        this, 
                        bind, 
                        ParseDataList(data));
        }

        /// <summary>
        /// Preenche uma data atrves do DTO
        /// </summary>
        /// <param name="data"></param>
        protected abstract List<ParserData> ParseDataList(IDataEntity data);
        

        /// <summary>
        /// A ser encapsulado pelo Fill() do Objeto Real
        /// </summary>
        /// <param name="data">EntityData</param>
        /// <param name="dto">Utilizar o "this" do objeto real</param>
        /// <param name="parser">Objeto de mapeamento</param>
        private void Parse(IDataEntity data, DataTransferObject dto, bool bind, List<ParserData> parser)
        {
            Type dataEntityType = data.GetType();
            Type dtoType = dto.GetType();
            var errorContext = string.Empty;

            try
            {
                foreach (var dataParser in parser)
                {

                    if (!bind)
                    {
                        var dataValue = dataEntityType.GetProperty(dataParser.DataPropertyIdentifier).GetValue(data, null);
                        dtoType.GetProperty(dataParser.DTOPropertyIdentifier).SetValue(dto, dataValue, null);
                    }
                    else
                    {
                        var dtoValue = dtoType.GetProperty(dataParser.DTOPropertyIdentifier).GetValue(dto, null);
                        dataEntityType.GetProperty(dataParser.DataPropertyIdentifier).SetValue(data, dtoValue, null);
                    }

                    errorContext = string.Format("Parser data: {0} dto: {1} with bind {2}", dataParser.DataPropertyIdentifier, dataParser.DTOPropertyIdentifier, bind.ToString());
                }
            }
            catch (Exception e)
            {
                throw new Exception(errorContext, e);
            }
        }


        public abstract object Clone();
        
    }
}
